package com.whjz.utils;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.whjz.annotation.Converter;
import com.whjz.annotation.Fill;
import com.whjz.annotation.IAfter;
import com.whjz.annotation.Super;
import com.whjz.common.IConverter;
import com.whjz.common.IFill;
import com.whjz.entity.ICommonAO;
import com.whjz.entity.IParamDTO;
import lombok.extern.java.Log;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

@Log
public class AOUtil {
    /**
     * 要忽略的父类
     */
    private static Set<Class> ignoreParentClasses = new HashSet<>();
    private static IParamDTO paramDTO;
    private static ICommonAO commonAO;
    private static Map fillExtraParams;

    static {
        ignoreParentClasses.add(Map.class);
        ignoreParentClasses.add(Number.class);
        ignoreParentClasses.add(String.class);
    }

    /**
     * AO类 填充服务类
     */
    private static Map<Class<? extends ICommonAO>, IFill> fillServices;

    /**
     * fillExtraParams为null
     * @see #parse(IParamDTO, Class, JSONObject, Map)
     */
    public static <T extends ICommonAO> T parse(IParamDTO paramDTO, Class<T> aoCls, JSONObject json) {
        return parse(paramDTO, aoCls, json, null);
    }

    /**
     * 解析
     * @param paramDTO 可为null
     * @param aoCls 结果的AO类
     * @param json 数据json
     * @param fillExtraParams 填充的额外变量
     */
    public static <T extends ICommonAO> T parse(IParamDTO paramDTO, Class<T> aoCls, JSONObject json, Map fillExtraParams) {
        T ao = json.getJSONObject("data").toJavaObject(aoCls);
        //完全解析
        parse(paramDTO, ao, fillExtraParams);
        return ao;
    }

    /**
     * @see #parse(IParamDTO, ICommonAO, Map)
     */
    public static void parse(ICommonAO commonAO) {
        parse(null, commonAO, null);
    }

    /**
     * 完全解析
     * 顺序:
     *   1. Super
     *   2. Converter
     *   3. IAfter
     *   4. IFill
     */
    public static void parse(IParamDTO paramDTO, ICommonAO commonAO, Map fillExtraParams) {
        //解析Super注解
        parseSuper(new ArrayList(), commonAO);

        //解析Converter转换器注解
        parseConverter(commonAO);

        //解析IAfter接口
        parseAfter(commonAO);

        //fill
        try {
            //fill(paramDTO, commonAO, fillExtraParams);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析其内的成员
     * (广度优先算法)
     */
    private static void parseSuper(List parents, Object root) {
        //检测null
        if (root == null) {
            return;
        }

        //检测忽略
        boolean ignore = false;
        for (Class cls:ignoreParentClasses) {
            if (cls.isAssignableFrom(root.getClass())) {
                ignore = true;
                break;
            }
        }
        if (ignore) {
            return;
        }

        //本身
        for (Field field:getFields(root.getClass())) {
            Super superAnnotation = field.getAnnotation(Super.class);
            if (superAnnotation != null) {
                Preconditions.checkArgument(superAnnotation.level() >= 1);
                Object parent = parents.get(parents.size() - superAnnotation.level());
                String fieldName = superAnnotation.field();
                if (fieldName.isEmpty()) {
                    fieldName = field.getName();
                }
                try {
                    Field valueField = parent.getClass().getDeclaredField(fieldName);
                    Object value = ReflectUtil.getField(valueField, parent);
                    ReflectUtil.setField(field, root, value);
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        //内部
        for (Field field:getFields(root.getClass())) {
            //忽略静态的变量
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            try {
                //null
                Object o = ReflectUtil.getField(field, root);
                if (o == null) {
                    continue;
                }

                //非null
                List subParents = new ArrayList(parents);
                subParents.add(root);

                //集合
                if (Collection.class.isAssignableFrom(field.getType())) {
                    for (Object e:(Collection) o) {
                        parseSuper(subParents, e);
                    }
                    continue;
                }

                //进入子类
                parseSuper(subParents, o);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 解析其内的成员
     * (广度优先算法)
     */
    private static void parseConverter(Object root) {
        //检测null
        if (root == null) {
            return;
        }

        //检测忽略
        boolean ignore = false;
        for (Class cls:ignoreParentClasses) {
            if (cls.isAssignableFrom(root.getClass())) {
                ignore = true;
                break;
            }
        }
        if (ignore) {
            return;
        }

        //本身
        for (Field field:getFields(root.getClass())) {
            Converter converterAnnotation = field.getAnnotation(Converter.class);
            if (converterAnnotation != null) {
                Class<? extends IConverter> converterCls = Preconditions.checkNotNull(converterAnnotation.value());
                IConverter converter = Preconditions.checkNotNull(SpringContextUtils.getBeanByClass(converterCls));
                try {
                    Object from = ReflectUtil.getField(field, root);
                    Object to = converter.convert(from);
                    ReflectUtil.setField(field, root, to);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        //内部
        for (Field field:getFields(root.getClass())) {
            try {
                //null
                Object o = ReflectUtil.getField(field, root);
                if (o == null) {
                    continue;
                }

                //非null

                //集合
                if (Collection.class.isAssignableFrom(field.getType())) {
                    for (Object e:(Collection) o) {
                        parseConverter(e);
                    }
                    continue;
                }

                //进入子类
                parseConverter(o);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * (深度优先算法)
     */
    private static void parseAfter(Object root) {
        //检测null
        if (root == null) {
            return;
        }

        //检测忽略
        boolean ignore = false;
        for (Class cls:ignoreParentClasses) {
            if (cls.isAssignableFrom(root.getClass())) {
                ignore = true;
                break;
            }
        }
        if (ignore) {
            return;
        }

        //内部
        for (Field field:getFields(root.getClass())) {
            try {
                //null
                Object o = ReflectUtil.getField(field, root);
                if (o == null) {
                    continue;
                }

                //非null

                //集合
                if (Collection.class.isAssignableFrom(field.getType())) {
                    for (Object e:(Collection) o) {
                        parseAfter(e);
                    }
                    continue;
                }

                //进入子类
                parseAfter(o);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        //本身
        if (IAfter.class.isAssignableFrom(root.getClass())) {
            try {
                IAfter iAfter = (IAfter) root;
                iAfter.onAfter();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 填充(如果某个服务类有Fill注解并且实现了IFill接口,那么就是填充服务类,会在对应的AO被解析后调用)
     * @param paramDTO 可能为null
     */
    private static void fill(IParamDTO paramDTO, ICommonAO commonAO, Map fillExtraParams) {
        initFill();

        IFill fillService = fillServices.get(commonAO.getClass());
        if (fillService != null) {
            if (fillExtraParams == null) {
                fillExtraParams = new HashMap();
            }
            try {
                fillService.fill(paramDTO, commonAO, fillExtraParams);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static void initFill() {
        //初始化(双重加锁)
        if (fillServices == null) {
            synchronized (AOUtil.class) {
                if (fillServices == null) {
                    fillServices = new HashMap<>();

                    Map<String, Object> map = SpringContextUtils.getBeansByAnnotation(Fill.class);
                    map.forEach((key, value) -> {
                        if (value instanceof IFill) {
                            Fill fill = value.getClass().getAnnotation(Fill.class);
                            fillServices.put(fill.value(), (IFill) value);
                            //日志
                            log.info("[Fill服务]注册: "+fill.value().getCanonicalName());
                        }
                    });
                }
            }
        }
    }

    /**
     * 获取要解析处理的变量列表
     */
    private static List<Field> getFields(Class cls) {
        return Lists.newArrayList(cls.getDeclaredFields()).stream().filter(field -> {
            //忽略静态的变量
            if (Modifier.isStatic(field.getModifiers())) {
                return false;
            }
            return true;
        }).collect(Collectors.toList());
    }
}
